package pokergame;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/Engine")
public class Engine extends HttpServlet{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	//GAME VARIABLES
	public static String move="0";
	static int[] ingame = {1, 1, 1, 1, 1, 1, 1, 1, 1};
	static int[] banks = {100, 100, 100, 100, 100, 100, 100, 100, 100};
	public static String playername="Unnamed";
	static int[] anal = {0, 0, 0, 0, 0};
	static int[] deck=new int[52];
	public static int[] plcards=new int[18];//Players cards
	public static int[] flopcards=new int[5];//Flop cards
	public static int dealer=(int)(Math.floor(Math.random()*9)+1);
	public static int player;
	
	//GAME LOGIC
	public static int nextdealer(){
		dealer++;
		if (dealer==10) dealer=1;
		return dealer;
	}
	public static void newcards(){
		//Deal cards to all players and flop
		int[] cards=new int[52];
		for (int i=0;i<52;i++){
			cards[i]=i;
		}
		for (int i=0;i<23;i++){
			int card=-1;
			while (card==-1){
				int cardnumber=(int)(Math.floor(Math.random()*52));
				card=cards[cardnumber];
				cards[cardnumber]=-1;
			}
			if (i<18){
				plcards[i]=card;
			}
			else{
				flopcards[i-18]=card;
			}
		}
	}
	public static int getFirstcard(int player){
		return plcards[player*2-2];
	}
	public static int getSecondcard(int player){
		return plcards[player*2-1];
	}
	
	//SERVLET
	public void init(ServletConfig config) throws ServletException {	
		super.init(config);
	}
	public void destroy() {
		 
	}
 
	public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
		Enumeration<?> enumu = request.getParameterNames();
		PrintWriter out = response.getWriter();//response
		while (enumu.hasMoreElements()) {
			String name = (String) enumu.nextElement();
			String values[] = request.getParameterValues(name);
			if (values != null) {
				if (name.equals("plcards")){
					String str="";
					for (int i=0;i<values.length;i++){
						int player = Integer.parseInt(values[i]);
						str+=getFirstcard(player)+" "+getSecondcard(player)+" "+player+" ";
					}
					out.println(str);
				}
				if (name.equals("nextdealer")){
					out.println(nextdealer()+" ");
					System.out.println("Next dealer");
					ChatServlet.messageSender.send(dealer+" is the Dealer");
				}
				if (name.equals("preflopdecide")){
					int l = preflopdecide();
					out.println(l);
					//System.out.println("Preflop decide "+l);
					String m;
					if (l==0) m="FOLDS";
					else if (l==1) m="CALLS";
					else m="RAISES";
					ChatServlet.messageSender.send(player+" "+m);
				}
				if (name.equals("flopcards")){
					int num = Integer.parseInt(values[0]);
					out.println(flopcards[num-1]);
					String m;
					if (num==0) m="FOLDS";
					else if (num==1) m="CALLS";
					else m="RAISES";
					ChatServlet.messageSender.send(player+" "+m);
				}
				if (name.equals("flopdecide")){
					int player = Integer.parseInt(values[0]);
					int l = flopanalys((player*2-2), (player*2-1));
					out.println(l);
					//System.out.println("Flop decide "+l);
					String m;
					if (Integer.parseInt(move)==0) m="FOLDS";
					else if (Integer.parseInt(move)==1) m="CALLS";
					else m="RAISES";
					ChatServlet.messageSender.send(player+" "+m);
				}
				
				if (name.equals("findwinner")){
					int l = findwinner();
					out.println(l);
					System.out.println("Winner "+l);
					ChatServlet.messageSender.send(l+" takes the BANK. WINNER.");
				}
				if (name.equals("gamestart")){
					String message=move+" "+dealer+" ";
					for (int i=0;i<ingame.length;i++) message+=ingame[i]+" ";
					for (int i=0;i<banks.length;i++) message+=banks[i]+" ";
					message+=playername+" ";
					out.println(message);
					System.out.println("For game restoring:");
					System.out.println(message);
					
				}
			}
		}

	}
	public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
		Enumeration<?> enumu = request.getParameterNames();
		while (enumu.hasMoreElements()) {
			String name = (String) enumu.nextElement();
			String values[] = request.getParameterValues(name);
			if (name.equals("newcards")){
				newcards();
				System.out.println("Deal new cards");
				ChatServlet.messageSender.send("0 Dealing cards");
			}
			if (name.equals("analys")){
				player = Integer.parseInt(values[0]);
				analys((player*2-2), (player*2-1));
				PrintWriter out = response.getWriter();//response
				out.println(1);
			}
			if (name.equals("move")){
				move=values[0];
				//System.out.println("move "+move);
				String m;
				if (Integer.parseInt(move)==0) m="Preflop";
				else if (Integer.parseInt(move)==1) m="Flop";
				else if (Integer.parseInt(move)==2) m="Turn";
				else m="River";
				ChatServlet.messageSender.send("0 now "+m);
			}
			if (name.equals("dealer")){
				dealer=Integer.parseInt(values[0]);
			}
			if (name.equals("ingame")){
				for (int i=0;i<values.length;i++){
					ingame[i]=Integer.parseInt(values[i]);
				}
			}
			if (name.equals("banks")){
				for (int i=0;i<values.length;i++){
					banks[i]=Integer.parseInt(values[i]);
				}
			}
			if (name.equals("plname")){
				playername=values[0];
				System.out.println("Players name: "+playername);
			}
			if (name.equals("chat")){
				String text=values[0];
				ChatServlet.messageSender.send("0 YOU: "+text);
			}
			if (name.equals("restart")){
				for (int i=0;i<ingame.length;i++){
					ingame[i]=1;
					banks[i]=100;
				}
				move="0";
				dealer=(int)(Math.floor(Math.random()*9)+1);
				PrintWriter out = response.getWriter();//response
				out.println(1);
				System.out.println(1);
			}
		}
	}



// 0 - fold, 1 - call, 2 - raise
public int preflopdecide(){
	String result = join(anal);
	if ((anal[0]==3) && (anal[1]==3)){			
			return 2;
		}
	
	else if (result.equals("22110") || result.equals("32110") || result.equals("22001") || result.equals("23110")){
			return 2;
		}
	
	else if (result.equals("11001") || result.equals("23310") || result.equals("32310") || result.equals("23310") || result.equals("11110")|| result.equals("22210") || result.equals("32210")){
		return 1;
	}
	else {
		return 0;
	}
}
public void analys(int card1, int card2){
		//Card analysys of the computer players
		if ((card1%13 <= 4) && (card1%13 >= 0)){
			anal[0] = 1;
		}
		if ((card2%13 <= 4) && (card2%13 >= 0)){
			anal[1] = 1;
		}

		if ((card1%13 <= 9) && (card1%13 >= 5)){
			anal[0] = 2;
		}
		if ((card2%13 <= 9) && (card2%13 >= 5)){
			anal[1] = 2;
		}

		if ((card1%13 <= 12) && (card1%13 >= 10)){
			anal[0] = 3;
		}
		if ((card2%13 <= 12) && (card2%13 >= 10)){
			anal[1] = 3;
		}

		if (card1%13 == card2%13){
			anal[4]=1;
			anal[2]=0;
			anal[3]=0;
		}
		else{
			if (card1<=12 && card2 <=12){
				anal[3]=1;
			}
			else if ((card1<=25 && card1>=13) && (card2 <=25 && card2>=13)){
				anal[3]=1;
			}
			else if ((card1<=38 && card1>=26) && (card2 <=38 && card2>=26)){
				anal[3]=1;
			}
			else if ((card1<=51 && card1>=39) && (card2 <=51 && card2>=39)){
				anal[3]=1;
			}
			else{
				anal[3]=0;
			}
			if (Math.abs(card1%13-card2%13)==1){
				anal[2]=1;
			}
			else if (Math.abs(card1%13-card2%13)==2){
				anal[2]=2;
			}
			else if (Math.abs(card1%13-card2%13)==3){
				anal[2]=3;
			}
			else{
				anal[2]=0;
			}
		}
	}
public int flopanalys(int card1, int card2){
		int[] cards = {0, 0, 0, 0, 0};
		cards[0] = flopcards[0]%13;
		cards[1] = flopcards[1]%13;
		cards[2] = flopcards[2]%13;
		cards[3] = card1%13;
		cards[4] = card2%13;
		
		Arrays.sort(cards);
		//trips or 4th
		if (((cards[0]==cards[1])&&(cards[1]==cards[2])) || ((cards[1]==cards[2])&&(cards[2]==cards[3])) || ((cards[2]==cards[3])&&(cards[3]==cards[4]))){
			return 2;//raise
		}
		// straight or straight flush or royal flush
		else if ((cards[4]-cards[0])== 4){
			return 2; 
		}
		//flush
		else if (card1<=12 && card2 <=12 && flopcards[0]<=12 && flopcards[1]<=12 && flopcards[2]<=12){
			return 2;
		}
		else if ((card1<=25 && card2<=25 && flopcards[0]<=25 && flopcards[1]<=25 && flopcards[2]<=25) && (card1>=12 && card2 >=12 && flopcards[0]>=12 && flopcards[1]>=12 && flopcards[2]>=12)){
			return 2;
		}
		else if ((card1>=26 && card2>=26 && flopcards[0]>=26 && flopcards[1]>=26 && flopcards[2]>=26) && (card1<=38 && card2 <=38 && flopcards[0]<=38 && flopcards[1]<=38 && flopcards[2]<=38)){
			return 2;
		}
		else if ((card1>=39 && card2>=39 && flopcards[0]>=39 && flopcards[1]>=39 && flopcards[2]>=39) && (card1<=51 && card2 <=51 && flopcards[0]<=51 && flopcards[1]<=51 && flopcards[2]<=51)){
			return 2;
		}
		//top pair or over pair or 2 pair
		else if ((card1%13==card2%13) || (card1%13==flopcards[2]%13) || (card2%13==flopcards[2]%13)){
			return 2;//call
		}
		//straight dro (2)
		else if (((cards[4]-cards[1])==3) && ((cards[3]-cards[0])==3)){
			return 1;// call
		}
		else{
			return 0;// fold
		}
	}	
public static int[] combanalys(int[] a){
	
	int[] b = {a[0], a[1], a[2], a[3], a[4]};
	// b sorted array without %13 sortNumber
	Arrays.sort(b);
	for (int i=0; i<a.length; i++){
		a[i]=a[i]%13;
	}
	Arrays.sort(a); // a sorted array with %13 sortNumber
	
	
	
	//Royal flush
	if ((b[4]-b[0]==4)&&(b[4]%13==12)){
		int[] l = {9,0};
		return l;
	}
	//Straight flush
	else if (b[4]-b[0]==4){
		int[] l = {8,b[4]%13};
		return l;
	}
	//4th
	else if ((a[0]==a[1]&&a[1]==a[2]&&a[2]==a[3])||(a[1]==a[2]&&a[2]==a[3]&&a[3]==a[4])){
		int[] l = {7, a[2]};
		return l;
	}
	// full house
	else if ((a[0]==a[1]&&a[2]==a[3]&&a[3]==a[4])){
		int[] l ={6,a[4],a[1]};
		return l;
	}
	else if ((a[0]==a[1]&&a[1]==a[2]&&a[3]==a[4])){
		int[] l = {6, a[1], a[4]};
		return l;
	}
	//flush
	else if (((b[4]<13))||((b[0]>12)&&(b[4]<26))||((b[0]>25)&&(b[4]<39))||(b[0]>38) && ifpair(a)==0){
		int[] l = {5,b[4]};
		return l;
	}
	//Straight
	else if(a[4]-a[0]==4 && ifpair(a)==0){
		int[] l = {4, a[4]};
		return l;
	}
	//Trips
	else if ((a[0]==a[1]&&a[1]==a[2])||(a[1]==a[2]&&a[2]==a[3])||(a[2]==a[3]&&a[3]==a[4])){
		int[] l = {3, a[2]};
		return l;
	}
	//2 Pair
	else if ((a[0]==a[1]&&a[2]==a[3])||(a[0]==a[1]&&a[3]==a[4])||(a[1]==a[2]&&a[3]==a[4])){
		int[] l = {2, a[3], a[1]};
		return l;
	}
	// Pair 
	else if (a[4]==a[3]){
		int[] l = {1, a[4], a[2]};
		return l;
	}
	else if (a[2]==a[3]){
		int[] l = {1, a[3], a[4]};
		return l;
	}
	else if (a[1]==a[2]){
		int[] l = {1, a[2], a[4]};
		return l;
	}
	else if (a[0]==a[1]){
		int[] l = {1, a[1], a[4]};
		return l;
	}
	// High card
	else{
		int[] l = {0,a[4]};
		return l;
	}
}
public static int[] playcomb(int player){
	int c1 = plcards[player*2-1];
	int c2 = plcards[player*2-2];
	int c3 = flopcards[0];
	int c4 = flopcards[1];
	int c5 = flopcards[2];
	int c6 = flopcards[3];
	int c7 = flopcards[4];
	
	int[] a1 = {c1, c2, c3, c4, c5};
	int[] a2 = {c1, c2, c3, c4, c7};
	int[] a3 = {c1, c2, c3, c4, c6};
	int[] a4 = {c1, c2, c3, c6, c7};
	int[] a5 = {c1, c2, c3, c5, c7};
	int[] a6 = {c1, c2, c3, c5, c6};
	int[] a7 = {c1, c2, c5, c6, c7};
	int[] a8 = {c1, c2, c4, c6, c7};
	int[] a9 = {c1, c2, c4, c5, c7};
	int[] a10 = {c1, c2, c4, c5, c6};
	int[] a11 = {c1, c4, c5, c6, c7};
	int[] a12 = {c1, c3, c5, c6, c7};
	int[] a13 = {c1, c3, c4, c6, c7};
	int[] a14 = {c1, c3, c4, c5, c7};
	int[] a15 = {c1, c3, c4, c5, c6};
	int[] a16 = {c3, c4, c5, c6, c7};
	int[] a17 = {c2, c4, c5, c6, c7};
	int[] a18 = {c2, c3, c5, c6, c7};
	int[] a19 = {c2, c3, c4, c6, c7};
	int[] a20 = {c2, c3, c4, c5, c7};
	int[] a21 = {c2, c3, c4, c5, c6};
	
	int[][] array = {combanalys(a1), combanalys(a2),
	         combanalys(a3), combanalys(a4),
	         combanalys(a5), combanalys(a6),
	         combanalys(a7), combanalys(a8),
	         combanalys(a9), combanalys(a10),
	         combanalys(a11), combanalys(a12),
	         combanalys(a13), combanalys(a14),
	         combanalys(a15), combanalys(a16),
	         combanalys(a17), combanalys(a18),
	         combanalys(a19), combanalys(a20),
	         combanalys(a21),};
	sort(array);
	return array[20];
}
public static int findwinner(){
	int ut = 0;
    int[][] arr = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
	arr[0] = playcomb(1);
    arr[1] = playcomb(2);
    arr[2] = playcomb(3);
    arr[3] = playcomb(4);
    arr[4] = playcomb(5);
    arr[5] = playcomb(6);
    arr[6] = playcomb(7);
    arr[7] = playcomb(8);
    arr[8] = playcomb(9);
    for (int i=0; i<9; i++){
    	if (ingame[i]==0){
    		int[] ku = {0,0};
    		arr[i]=ku;
    	}
    }
    int[][] arr2 = {arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7], arr[8]};
    System.out.println("Unsorted");
    for (int i=0; i<9; i++){
    	System.out.println(arr[i][0]+" "+arr[i][1]);
    }
    arr2=sort(arr2);
    System.out.println("Sorted");
    for (int i=0; i<9; i++){
    	System.out.println(arr2[i][0]+" "+arr2[i][1]);
    }
    for (int i=0; i<arr.length; i++){
        if (join(arr2[arr2.length-1]).equals(join(arr[i]))){
        		ut = i+1;
        }
    }
    return ut;
}


public static void shuffle(){
	for (int i=0; i<52; i++){
		deck[i]=i;
	}
	for (int i=0; i<52; i++){
		int k = (int)(Math.floor(Math.random()*51));
		int a = deck[i];
		int b = deck[k];
		deck[k]=a;
		deck[i]=b;
	}
}
public static void setplcards(){
	for (int i=0; i<18; i++){
		plcards[i]=deck[i];
	}
}
public static void setflopcards(){
	for (int i=0; i<5; i++){
		flopcards[i]=deck[i+18];
	}
}

public static int ifpair(int[] a){
	if (a[4]==a[3]){
		return 1;
	}
	else if (a[2]==a[3]){
		return 1;
	}
	else if (a[1]==a[2]){
		return 1;
	}
	else if (a[0]==a[1]){
		return 1;
	}
	else{
		return 0;
	}
}
public static String join(int[] massiiv){
	String str="";
	for (int i=0;i<massiiv.length;i++){
	str+=Integer.toString(massiiv[i]);
	}
	return str;
	}
public static int[][] sort(int[][] massiiv){
	//This function sorts integer arrays of length 2 or 3 exactly.
	int i=1;
	int[] tmp={};
	boolean replace=false;
	while (i!=massiiv.length){
		if (massiiv[i-1][0]>massiiv[i][0]){
			replace=true;
		}
		else if (massiiv[i-1][0]==massiiv[i][0]){
				if (massiiv[i-1][1]>massiiv[i][1]){
					replace=true;
				}
				else if (massiiv[i-1][1]==massiiv[i][1]){
					try {
						int a=massiiv[i-1][2];
						try {
							int b=massiiv[i][2];
							if (a>b){
								replace=true;
							}
							else{
								replace=false;
							}
						} catch (ArrayIndexOutOfBoundsException e) {
							replace=true;
						}
					} catch (ArrayIndexOutOfBoundsException e) {
						replace=false;
					}
				}
				else{
					replace=false;
				}
		}
		else{
			replace=false;
		}
		if (replace==true){
			tmp=massiiv[i-1].clone();
			massiiv[i-1]=massiiv[i].clone();
			massiiv[i]=tmp.clone();
			i--;
		}
		else{
			i++;
		}
		if (i==0){
			i=1;
		}
	}
	return massiiv;
}
}

